﻿using System;
using System.Runtime.InteropServices;

namespace Nextensions.WinApi.Input
{
    public class KeyboardHook: HookBase
    {
        public delegate void KeyboardEventHandler(KeyboardEvent eventType, uint timestamp, byte key);
        public event KeyboardEventHandler KeyboardEventOccured;

        override public bool Start()
        {
            _hookProc = new Win.HookProc(KeyboardHookLowlevel);
            _hHook = Win.SetWindowsHookEx(HookType.WH_KEYBOARD_LL, _hookProc, (IntPtr)0, 0);
            return _hHook.ToInt32() != 0;
        }

        private int KeyboardHookLowlevel(int nCode, IntPtr wParam, IntPtr lParam)
        {
            KBDLLHOOKSTRUCT ll = (KBDLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT));

            if (nCode < 0)
            {
                return Win.CallNextHookEx(_hHook, nCode, wParam, lParam);
            }
            else
            {
                KeyboardEvent eventType = KeyboardEvent.None;

                switch (wParam.ToInt32())
                {
                    case (int)WM.KEYDOWN:

                        eventType = KeyboardEvent.KeyDown;
                        break;

                    case (int)WM.KEYUP:

                        eventType = KeyboardEvent.KeyUp;
                        break;
                }

                if (eventType != KeyboardEvent.None)
                    KeyboardEventOccured(eventType, ll.time, (byte)ll.vkCode);

                // Return non-zero to prevent actions from reaching next procedure
                if (!CallNextHook)
                    return 1;

                return Win.CallNextHookEx(_hHook, nCode, wParam, lParam);
            }

            //return Win.CallNextHookEx(_hHook, nCode, wParam, lParam);
        }

        public KeyboardHook()
            : base()
        {
        }
    }
}
